package com.ysstech.etfmanage.service.impl;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ysstech.common.exception.BusinessException;
import com.ysstech.common.service.HolidayService;
import com.ysstech.common.util.BigDecimalUtil;
import com.ysstech.common.util.DateUtil;
import com.ysstech.etfmanage.entity.Account;
import com.ysstech.etfmanage.entity.AccountVo;
import com.ysstech.etfmanage.entity.ParamVo;
import com.ysstech.etfmanage.entity.SettlementDetailed;
import com.ysstech.etfmanage.entity.Skep;
import com.ysstech.etfmanage.enums.EtfAccountCode;
import com.ysstech.etfmanage.enums.EtfManageEnum;
import com.ysstech.etfmanage.enums.EtfReplaceCodeEnum;
import com.ysstech.etfmanage.feign.FeignValuationService;
import com.ysstech.etfmanage.feign.entity.FuturesDealDetailed;
import com.ysstech.etfmanage.feign.entity.Quotation;
import com.ysstech.etfmanage.service.AccountService;
import com.ysstech.etfmanage.service.SettlementDetailedService;
import com.ysstech.etfmanage.service.SkepService;
import com.ysstech.etfmanage.thread.EtfAccountGenerateService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

@Slf4j
@Service
public class SzGoodsFuturesAccountServiceImpl extends EtfAccountGenerateService<AccountVo> {

    @Autowired
    private AccountService accountService;
    @Autowired
    private SettlementDetailedService settlementDetailedService;
    @Autowired
    private SkepService skepService;
    @Autowired
    private HolidayService holidayService;
    @Autowired
    private FeignValuationService feignValuationService;

    /**
     * ETF 类型
     *
     * @return
     */
    public EtfAccountCode getFtype() {
        return EtfAccountCode.SZ_GOODS_FUTURES_ETF;
    }

    /**
     * 成份券市场
     *
     * @return
     */
    public List<String> getMarketList() {
        return null;
    }

    /**
     * 初始化台账
     *
     * @param vo
     * @param paramVo
     * @throws Exception
     */
    public List<AccountVo> initEtfAccount(Account vo, ParamVo paramVo) throws Exception {
        Account account = new Account();
        account.setPurchaseDate(vo.getPurchaseDate());
        account.setAccountId(vo.getAccountId());
        account.setEtfType(paramVo.getEtfType());
        account.setEtfMode(paramVo.getEtfMode());
        account.setEtfMarket(paramVo.getEtfMarket());
        account.setReplaceCode(EtfReplaceCodeEnum.S_REPLACE_CODE_ONE.getCode()); //需要替代的券
        List<Account> initList = accountService.queryFuturesInitList(account);
        //按照申购和赎回分开
        List<Account> listPurchaseData = new ArrayList<>();
        List<Account> listRedeemData = new ArrayList<>();
        String yesterday = holidayService.getNextWorkday(vo.getPurchaseDate(), -1);
        List<AccountVo> voList = new ArrayList<>();
        for (Account bean : initList) {
            if (null == bean) {
                continue;
            }
            BigDecimal amount = BigDecimalUtil.subtract(BigDecimalUtil.divide(
                    BigDecimalUtil.multiply(bean.getShareAmount(), bean.getOneLevelSecurityCodeAmount()), paramVo.getEtfBenchmarkScale(), 0)
                    , bean.getDealAmount());
            if (BigDecimalUtil.compareTo(amount, BigDecimal.ZERO) <= 0) {
                continue;
            }
            bean.setAmount(amount);
            bean.setPurchaseDate(vo.getPurchaseDate());
            bean.setReplaceMoney(this.handleInitReplaceMoney(bean, paramVo, yesterday)); //替代金额
            Quotation quotation = accountService.queryQuotation(vo.getPurchaseDate(), bean.getSecurityCode());
            if (null == quotation) {
                continue;
            }
            //今日行情
            BigDecimal unitCost = (1 == paramVo.getEtfOrganizationPrice()) ? quotation.getQuotationClosingPrice()
                    : quotation.getQuotationAveragePrice();
            // 单位成本=行情*合约乘数
            bean.setUnitCost(BigDecimalUtil.multiply(unitCost, bean.getContractMultiplier()));
            //可退替代金額=(替代金额－数量×单位成本（当日行情）*合约乘数)*（申赎方向）
            bean.setReplaceableMoney(BigDecimalUtil.multiply(BigDecimalUtil.subtract(bean.getReplaceMoney(),
                    BigDecimalUtil.multiply(amount, bean.getUnitCost())),
                    EtfManageEnum.ETF_PURCHASE.getCode().equals(bean.getBusinessType()) ? new BigDecimal("1") : new BigDecimal("-1")));
            bean.setFdate(DateUtil.strToLocalDate(vo.getPurchaseDate()));
            bean.setClearCode(EtfManageEnum.ETF_CLEAR_CODE_NO.getCode());
            bean.setSurplusAmount(amount);
            bean.setAddTime(LocalDateTime.now());
            bean.setRate(BigDecimal.ONE);
            bean.setEtfType(paramVo.getEtfType());
            bean.setEtfMode(paramVo.getEtfMode());
            bean.setEtfMarket(paramVo.getEtfMarket());
            bean.setId(DateUtil.generateUUID());
            if (EtfManageEnum.ETF_PURCHASE.getCode().equals(bean.getBusinessType())) {
                listPurchaseData.add(bean);
            } else {
                listRedeemData.add(bean);
            }
        }
        //查询申购和赎回总的替代金额
        Map<String, BigDecimal> sumReplaceMoneyMap = this.querySumReplaceMoney(vo, paramVo);
        AccountVo etfPurchase = new AccountVo();
        etfPurchase.setList(listPurchaseData);
        etfPurchase.setParamVo(paramVo);
        etfPurchase.setSumReplaceMoney(sumReplaceMoneyMap.get(EtfManageEnum.ETF_PURCHASE.getCode()));
        voList.add(etfPurchase);
        AccountVo etfRedeem = new AccountVo();
        etfRedeem.setList(listRedeemData);
        etfRedeem.setParamVo(paramVo);
        etfRedeem.setSumReplaceMoney(sumReplaceMoneyMap.get(EtfManageEnum.ETF_REDEMPTION.getCode()));
        voList.add(etfRedeem);
        return voList;
    }

    @Override
    public List<AccountVo> renewRightEtfAccount(Account vo, ParamVo paramVo) throws Exception {
        return null;
    }

    /**
     * 更新跨市场ETF台账补票信息
     *
     * @param vo
     * @return
     */
    public List<AccountVo> renewFillEtfAccount(Account vo, ParamVo paramVo) throws Exception {
        log.info("更新" + vo.getPurchaseDate() + "深圳商品期货ETF台账补票数据开始");
        List<AccountVo> voList = new ArrayList<>();
        vo.setMarket(null);
        List<Account> list = accountService.queryEtfAccountFill(vo, paramVo);
        if (CollectionUtils.isEmpty(list)) {
            return voList;
        }
        vo.setDealSeat(paramVo.getEtfFillSeat());
        AccountVo accountVo = new AccountVo();
        FuturesDealDetailed futuresDealDetailed = new FuturesDealDetailed();
        futuresDealDetailed.setAccountId(vo.getAccountId());
        futuresDealDetailed.setTransactionDate(DateUtil.strToLocalDate(vo.getPurchaseDate()));
        accountVo.setMapFillDetail(feignValuationService.queryFuturesDealDetailed(futuresDealDetailed));
        accountVo.setParamVo(paramVo);
        accountVo.setList(list);
        voList.add(accountVo);

        log.info("更新" + vo.getPurchaseDate() + "深圳商品期货ETF台账补票数据结束");
        return voList;
    }

    /**
     * 计算替代金额
     *
     * @param vo
     * @param paramVo
     * @return
     * @throws Exception
     */
    private BigDecimal handleInitReplaceMoney(Account vo, ParamVo paramVo, String yesterday) throws Exception {
        Quotation quotation = accountService.queryQuotation(yesterday, vo.getSecurityCode());
        if (null == quotation) {
            return BigDecimal.ZERO;
        }
        BigDecimal organizationPrice = (1 == paramVo.getEtfOrganizationPrice()) ? quotation.getQuotationClosingPrice()
                : quotation.getQuotationAveragePrice();
        if (EtfManageEnum.ETF_PURCHASE.getCode().equals(vo.getBusinessType())) {
            if (BigDecimalUtil.compareTo(vo.getPurchaseReplaceMoney(), BigDecimal.ZERO) == 0) {
                //申购的替代金额 ReplaceAmount  dealAmount*(1+溢折价比例)*申赎日期的收盘价
                return BigDecimalUtil.multiply(BigDecimalUtil.multiply(BigDecimalUtil.multiply(vo.getAmount(), BigDecimalUtil.add(BigDecimal.ONE, new BigDecimal(vo.getPremiumScale())))
                        , organizationPrice), vo.getContractMultiplier(), Integer.valueOf(EtfManageEnum.ETF_MONEY_SCALE.getCode()));
            }
            return BigDecimalUtil.multiply(BigDecimalUtil.divide(BigDecimalUtil.multiply(vo.getPurchaseReplaceMoney(),
                    vo.getOneLevelSecurityCodeAmount()), paramVo.getEtfBenchmarkScale()),
                    vo.getContractMultiplier(), Integer.valueOf(EtfManageEnum.ETF_MONEY_SCALE.getCode()));
        }
        if (vo.getRedeemReplaceMoney().compareTo(BigDecimal.ZERO) == 0 && new BigDecimal(vo.getDiscountScale()).compareTo(BigDecimal.ZERO) != 0) {
            // 赎回的替代金额 dealAmount*(1-折折价比例)*申赎日期的收盘价
            return BigDecimalUtil.multiply(BigDecimalUtil.multiply(BigDecimalUtil.multiply(vo.getAmount(), BigDecimalUtil.subtract(BigDecimal.ONE, new BigDecimal(vo.getDiscountScale())))
                    , organizationPrice), vo.getContractMultiplier(), Integer.valueOf(EtfManageEnum.ETF_MONEY_SCALE.getCode()));
        }
        if (vo.getRedeemReplaceMoney().compareTo(BigDecimal.ZERO) == 0 && new BigDecimal(vo.getDiscountScale()).compareTo(BigDecimal.ZERO) == 0) {
            return BigDecimalUtil.multiply(BigDecimalUtil.multiply(organizationPrice, BigDecimalUtil.multiply(vo.getAmount(),
                    BigDecimalUtil.subtract(BigDecimal.ONE, new BigDecimal(vo.getPremiumScale()))))
                    , vo.getContractMultiplier(), Integer.valueOf(EtfManageEnum.ETF_MONEY_SCALE.getCode()));
        }
        return BigDecimalUtil.multiply(BigDecimalUtil.divide(BigDecimalUtil.multiply(vo.getRedeemReplaceMoney(), vo.getOneLevelSecurityCodeAmount()),
                paramVo.getEtfBenchmarkScale()), vo.getContractMultiplier(), Integer.valueOf(EtfManageEnum.ETF_MONEY_SCALE.getCode()));
    }

    /**
     * ETF 获取申购和数据的汇总替代金额
     *
     * @param vo
     * @param paramVo
     * @return
     * @throws Exception
     */
    private Map<String, BigDecimal> querySumReplaceMoney(Account vo, ParamVo paramVo) throws Exception {
        Map<String, BigDecimal> map = new HashMap<>();
        try {
            map.put(EtfManageEnum.ETF_PURCHASE.getCode(), BigDecimal.ZERO);
            map.put(EtfManageEnum.ETF_REDEMPTION.getCode(), BigDecimal.ZERO);
            List<SettlementDetailed> dealDetaildList = settlementDetailedService.querySumReplaceMoneyAndAmount(vo.getPurchaseDate(), paramVo);
            //查询篮子里必须现金替代的替代金额
            QueryWrapper<Skep> wrapperEtfSkep = new QueryWrapper<>();
            wrapperEtfSkep.select("SUM(PURCHASE_REPLACE_MONEY) as purchaseReplaceMoney", "SUM(PURCHASE_REPLACE_MONEY) as redeemReplaceMoney");
            wrapperEtfSkep.eq("ACCOUNT_ID", vo.getAccountId());
            wrapperEtfSkep.in("REPLACE_CODE", Arrays.asList(EtfReplaceCodeEnum.S_REPLACE_CODE_TWO.getCode()));
            wrapperEtfSkep.eq("ETF_MARKET", paramVo.getEtfMarket());
            wrapperEtfSkep.eq("ETF_MODE", paramVo.getEtfMode());
            wrapperEtfSkep.eq("ETF_TYPE", paramVo.getEtfType());
            wrapperEtfSkep.eq("FDATE", vo.getPurchaseDate());
            wrapperEtfSkep.ne("SECURITY_CODE", "159900");
            Skep gpSkepSumReplaceMoney = skepService.getOne(wrapperEtfSkep);
            if (null == gpSkepSumReplaceMoney) {
                return map;
            }
            //分别计算申购和赎回篮子数
            for (SettlementDetailed settlementDetailed : dealDetaildList) {
                if (null == settlementDetailed) {
                    continue;
                }
                BigDecimal etfSkepAmount = settlementDetailed.getTransferAmount().divide(paramVo.getEtfBenchmarkScale());
                if (EtfManageEnum.ETF_PURCHASE.getCode().equals(settlementDetailed.getBusinessType())) {
                    map.put(settlementDetailed.getBusinessType(), settlementDetailed.getDealMoney().subtract(gpSkepSumReplaceMoney.getPurchaseReplaceMoney().multiply(etfSkepAmount)));
                    continue;
                } else if (EtfManageEnum.ETF_REDEMPTION.getCode().equals(settlementDetailed.getBusinessType())) {
                    map.put(settlementDetailed.getBusinessType(), settlementDetailed.getDealMoney().subtract(gpSkepSumReplaceMoney.getRedeemReplaceMoney().multiply(etfSkepAmount)));
                    continue;
                }
            }
        } catch (Exception ex) {
            log.error("计算交易文件中申购和赎回汇总额替代金额出错：" + ex.toString());
            throw new BusinessException("计算交易文件中申购和赎回汇总额替代金额出错,请稍后重试！");
        }
        return map;
    }
}
